#pragma once

#include <EditorFramework/EditorFrameworkDLL.h>

#include <Foundation/Reflection/Implementation/StaticRTTI.h>
#include <Foundation/Strings/HashedString.h>
#include <Foundation/Strings/String.h>
#include <Foundation/Time/Timestamp.h>
#include <Foundation/Types/Bitflags.h>
#include <Foundation/Types/Uuid.h>

class ezImage;
class ezAssetFileHeader;

struct ezAssetExistanceState
{
  using StorageType = ezUInt8;

  enum Enum : ezUInt8
  {
    FileAdded,
    FileRemoved,
    FileMoved,
    FileModified,
    FileUnchanged,
  };
};

struct ezAssetDocumentFlags
{
  using StorageType = ezUInt8;

  enum Enum
  {
    None = 0,
    AutoTransformOnSave = EZ_BIT(0),               ///< Every time the document is saved, TransformAsset is automatically executed
    DisableTransform = EZ_BIT(1),                  ///< If set, TransformAsset will not do anything
    OnlyTransformManually = EZ_BIT(2),             ///< The asset transformation is not done, unless explicitly requested for this asset
    SupportsThumbnail = EZ_BIT(3),                 ///< The asset supports thumbnail generation (InternalCreateThumbnail must be implemented).
    AutoThumbnailOnTransform = EZ_BIT(4),          ///< Thumbnail is automatically generated by the asset transform, and does not need to be explicitly created.
    SubAssetsSupportThumbnail = EZ_BIT(5),         ///< The sub-asset supports thumbnail generation (InternalCreateThumbnail must be implemented).
    SubAssetsAutoThumbnailOnTransform = EZ_BIT(6), ///< Thumbnails for sub-assets are automatically generated by the asset transform, and do not need to be explicitly created.
    Default = None
  };

  struct Bits
  {
    StorageType AutoTransformOnSave : 1;
    StorageType DisableTransform : 1;
    StorageType OnlyTransformManually : 1;
    StorageType SupportsThumbnail : 1;
    StorageType AutoThumbnailOnTransform : 1;
    StorageType SubAssetsSupportThumbnail : 1;
    StorageType SubAssetsAutoThumbnailOnTransform : 1;
  };
};

EZ_DECLARE_FLAGS_OPERATORS(ezAssetDocumentFlags);

struct ezTransformFlags
{
  using StorageType = ezUInt8;

  enum Enum
  {
    None = 0,
    TriggeredManually = EZ_BIT(0),    ///< Transform triggered by user directly. Needs to be set to transform assets marked with
                                      ///< ezAssetDocumentFlags::Enum::OnlyTransformManually.
    ForceTransform = EZ_BIT(1),       ///< Will transform the asset regardless of its current transform state.
    BackgroundProcessing = EZ_BIT(2), ///< If changes need to be made that requires re-saving the asset transform will be aborted and ezTransformResult::NeedsImport is returned.
    Default = None
  };

  struct Bits
  {
    StorageType TriggeredManually : 1;
    StorageType ForceTransform : 1;
    StorageType BackgroundProcessing : 1;
  };
};
EZ_DECLARE_FLAGS_OPERATORS(ezTransformFlags);

struct ezSubAssetData
{
  ezUuid m_Guid;
  ezHashedString m_sSubAssetsDocumentTypeName;
  ezString m_sName;
};

struct EZ_EDITORFRAMEWORK_DLL ezAssetDocumentTypeDescriptor : public ezDocumentTypeDescriptor
{
  ezAssetDocumentTypeDescriptor() = default;
  ~ezAssetDocumentTypeDescriptor() = default;

  ezString m_sResourceFileExtension;
  ezBitflags<ezAssetDocumentFlags> m_AssetDocumentFlags;
};


struct ezTransformResult
{
  using StorageType = ezUInt8;

  enum Enum : ezUInt8
  {
    Success = 0,
    Failure,
    NeedsImport,
    Default = Success,
  };
};
EZ_DECLARE_REFLECTABLE_TYPE(EZ_EDITORFRAMEWORK_DLL, ezTransformResult);


struct EZ_EDITORFRAMEWORK_DLL ezTransformStatus
{
  EZ_ALWAYS_INLINE explicit ezTransformStatus()
    : m_Result(ezTransformResult::Success)
  {
  }

  explicit ezTransformStatus(const char* szError)
    : m_Result(ezTransformResult::Failure)
    , m_sMessage(szError)
  {
  }

  explicit ezTransformStatus(ezTransformResult::Enum r, ezStringView sError)
    : m_Result(r)
    , m_sMessage(sError)
  {
  }

  explicit ezTransformStatus(ezStringView sError)
    : m_Result(ezTransformResult::Failure)
    , m_sMessage(sError)
  {
  }

  EZ_ALWAYS_INLINE ezTransformStatus(ezTransformResult::Enum r)
    : m_Result(r)
  {
  }

  EZ_ALWAYS_INLINE ezTransformStatus(ezStatus r)
    : m_Result(r.Succeeded() ? ezTransformResult::Success : ezTransformResult::Failure)
    , m_sMessage(r.GetMessageString())
  {
  }

  EZ_ALWAYS_INLINE ezTransformStatus(ezResult r)
    : m_Result(r.Succeeded() ? ezTransformResult::Success : ezTransformResult::Failure)
  {
  }

  EZ_ALWAYS_INLINE ezTransformStatus(ezResultEnum r)
    : m_Result(r == EZ_SUCCESS ? ezTransformResult::Success : ezTransformResult::Failure)
  {
  }

  explicit ezTransformStatus(const ezFormatString& fmt)
    : m_Result(ezTransformResult::Failure)
  {
    ezStringBuilder sMsg;
    m_sMessage = fmt.GetText(sMsg);
  }

  EZ_ALWAYS_INLINE bool Succeeded() const { return m_Result == ezTransformResult::Success; }
  EZ_ALWAYS_INLINE bool Failed() const { return m_Result == ezTransformResult::Failure; }

  ezEnum<ezTransformResult> m_Result;
  ezString m_sMessage;
};
EZ_DECLARE_REFLECTABLE_TYPE(EZ_EDITORFRAMEWORK_DLL, ezTransformStatus);

EZ_ALWAYS_INLINE ezResult ezToResult(const ezTransformStatus& result)
{
  return result.m_Result == ezTransformResult::Success ? EZ_SUCCESS : EZ_FAILURE;
}
